using DocumentCreationSystem.Models;
using Microsoft.Extensions.Logging;

namespace DocumentCreationSystem.Services
{
    /// <summary>
    /// 记忆系统编排器：根据配置选择具体实现（内置或 Ai00Mem）
    /// </summary>
    public class MemoryOrchestrator : IMemoryService
    {
        private readonly ILogger<MemoryOrchestrator> _logger;
        private readonly BuiltInMemoryService _builtIn;
        private readonly Ai00MemAdapter _ai00;
        private IMemoryService _active = null!;
        private MemoryConfig _config = new();
        private DateTime _nextAi00ProbeAt = DateTime.MinValue;

        public MemoryOrchestrator(
            ILogger<MemoryOrchestrator> logger,
            BuiltInMemoryService builtIn,
            Ai00MemAdapter ai00)
        {
            _logger = logger; _builtIn = builtIn; _ai00 = ai00;
        }

        public async Task<bool> InitializeAsync(MemoryConfig config)
        {
            _config = config ?? new MemoryConfig();
            if (!_config.Enabled)
            {
                _active = _builtIn; // 关闭时仍允许调用但不作为强依赖
                _logger.LogInformation("记忆系统未启用，将使用内置占位实现");
                return await _active.InitializeAsync(new MemoryConfig { Enabled = false, SimilarityThreshold = _config.SimilarityThreshold, TopK = _config.TopK });
            }

            if (string.Equals(_config.Provider, "Ai00Mem", StringComparison.OrdinalIgnoreCase))
            {
                _logger.LogInformation("优先使用 Ai00Mem 适配器");
                var ok = await _ai00.InitializeAsync(_config);
                if (ok)
                {
                    _active = _ai00;
                    _nextAi00ProbeAt = DateTime.UtcNow; // 健康
                    return true;
                }
                _logger.LogWarning("Ai00Mem 初始化失败，自动回退到内置记忆实现");
                _nextAi00ProbeAt = DateTime.UtcNow.AddSeconds(30); // 30s 后尝试半开路
            }

            _active = _builtIn;
            return await _active.InitializeAsync(_config);
        }

        public async Task<string> AddMemoryAsync(string content, string? userId = null, string? sessionId = null, Dictionary<string, object>? attributes = null)
        {
            try
            {
                await TryHalfOpenProbeAsync();
                return await _active.AddMemoryAsync(content, userId, sessionId, attributes);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "记忆写入失败，尝试回退内置实现重试一次");
                if (!ReferenceEquals(_active, _builtIn))
                {
                    _active = _builtIn;
                    await _active.InitializeAsync(_config);
                    return await _active.AddMemoryAsync(content, userId, sessionId, attributes);
                }
                throw;
            }
        }

        public async Task<List<MemoryResult>> QueryAsync(string query, string? userId = null, int topK = 5, float threshold = 0.7f)
        {
            var k = topK > 0 ? topK : _config.TopK;
            var th = threshold > 0 ? threshold : _config.SimilarityThreshold;
            try
            {
                await TryHalfOpenProbeAsync();
                return await _active.QueryAsync(query, userId, k, th);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "记忆检索失败，尝试回退内置实现重试一次");
                if (!ReferenceEquals(_active, _builtIn))
                {
                    _active = _builtIn;
                    await _active.InitializeAsync(_config);
                    return await _active.QueryAsync(query, userId, k, th);
                }
                throw;
            }
        }

        private async Task TryHalfOpenProbeAsync()
        {
            // 若当前不是 Ai00Mem，且到达探测窗口，则尝试健康检查以便自动恢复
            if (!ReferenceEquals(_active, _ai00) && string.Equals(_config.Provider, "Ai00Mem", StringComparison.OrdinalIgnoreCase))
            {
                if (DateTime.UtcNow >= _nextAi00ProbeAt)
                {
                    _nextAi00ProbeAt = DateTime.UtcNow.AddSeconds(30);
                    try
                    {
                        if (await _ai00.InitializeAsync(_config))
                        {
                            _logger.LogInformation("Ai00Mem 恢复可用，切回 Ai00Mem");
                            _active = _ai00;
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogDebug(ex, "半开路探测失败，继续使用内置实现");
                    }
                }
            }
        }
    }
}

